package com.videomaru
{
	import com.videomaru.media.PlayFLV;
	
	import flash.display.Sprite;
	
	/**
	* Dispatched when the volume is changed
	*
	* @eventType com.videomaru.PlayerEvent.VOLUME_CHANGE
	*/
	[Event(name="onVolumeChange", type="com.videomaru.PlayerEvent.VOLUME_CHANGE")]
	
	/**
	* Dispatched when we have received the extra information (Metadata) embedded in the FLV file.
	*
	* @eventType com.videomaru.PlayerEvent.METADATA
	*/
	[Event(name="onMetaData", type="com.videomaru.PlayerEvent.METADATA")]
	
	/**
	* Dispatched when a file has played to the end
	*
	* @eventType com.videomaru.PlayerEvent.COMPLETE
	*/
	[Event(name="onComplete", type="com.videomaru.PlayerEvent.COMPLETE")]
	
	/**
	* Dispatched when we have received the actual height and width of the video, so the aspect may be set
	*
	* @eventType com.videomaru.PlayerEvent.ASPECT
	*/
	[Event(name="onAspect", type="com.videomaru.PlayerEvent.ASPECT")]
	
	/**
	* Dispatched when the video starts playing, either from the start or resuming an existing play operation
	*
	* @eventType com.videomaru.PlayerEvent.START
	*/
	[Event(name="onStart", type="com.videomaru.PlayerEvent.START")]
	
	/**
	* Dispatched when the video is paused
	*
	* @eventType com.videomaru.PlayerEvent.PAUSE
	*/
	[Event(name="onPause", type="com.videomaru.MaruEvent.PAUSE")]
	
	/**
	* Dispatched when playback stops
	*
	* @eventType com.videomaru.MaruEvent.STOP
	*/
	[Event(name="onStop", type="com.videomaru.MaruEvent.STOP")]
	
	/**
	* Dispatched when a seek opperation has ended
	*
	* @eventType com.videomaru.MaruEvent.SEEK
	*/
	[Event(name="onSeek", type="com.videomaru.MaruEvent.SEEK")]
	
	/**
	* Dispatched on every ENTER_FRAME, but only if the value is changed. Contains the percentage played as the 'value' parameter.
	*
	* @eventType com.videomaru.MaruEvent.PLAY_PROGRESS
	*/
	[Event(name="onPlayProgress", type="com.videomaru.MaruEvent.PLAY_PROGRESS")]
	
	/**
	* Dispatched on every ENTER_FRAME, but only if the value is changed. Contains the percentage of buffer filled as the 'value' parameter.
	*
	* @eventType com.videomaru.MaruEvent.BUFFER_PROGRESS
	*/
	[Event(name="onBufferProgress", type="com.videomaru.MaruEvent.BUFFER_PROGRESS")]
	
	/**
	* Dispatched on every ENTER_FRAME, but only if the value is changed. Contains the percentage downloaded as the 'value' parameter.
	*
	* @eventType com.videomaru.MaruEvent.DOWNLOAD_PROGRESS
	*/
	[Event(name="onDownloadProgress", type="com.videomaru.MaruEvent.DOWNLOAD_PROGRESS")]
	
	/**
	* Dispatched when a file fails to load. Usually because of a typo or that the file simply is not at the URL specified.
	*
	* @eventType com.videomaru.MaruEvent.IO_ERROR
	*/
	[Event(name="onIOError", type="com.videomaru.MaruEvent.IO_ERROR")]
	
	/**
	* Dispatched when a file fails to load due to a security violation.
	* <p>This usually means that you have tried to load an file from a website that does not allow you to use their files. This can often be fixed if the website publishes a special file with the name 'crossdomain.xml'. See <a href="http://www.crossdomainxml.org/" target="_blank">http://www.crossdomainxml.org/</a> or <a href="http://livedocs.adobe.com/flash/9.0/main/00000347.html" target="_blank">Adobe's technote</a> for more information.</p>  
	*
	* @eventType com.videomaru.MaruEvent.SECURITY_ERROR
	*/
	[Event(name="onSecurityError", type="com.videomaru.MaruEvent.SECURITY_ERROR")]
	
	/*
		not yet implemented:
		* @event onClose
		* @event onForward
		* @event onInit
		* @event onReady
		* @event onResume
		* @event onRewind
		* @event onScrubStart (partially, via SEEK)
		* @event onScrubStop  (partially, via SEEK)
		* @event onStateChange
		*/
	
	
	/**
	 * com.videomaru.MaruPlayer
	 * This is the basic video player class used in the video.Maru component. The class can also be used as a simple way to build media playback solutions using Actionscript 3 as well. If you use a good editor such as Flex, FDT or FlashDevelop (not the Flash CS3 IDE), you'll get full code hinting and easy access to all the methods supported. You can also find tutorials and info at http://www.videomaru.com
	 * @example <p>To create a video player directly, just type:</p>
	 * <code><pre>import com.videomaru.MaruPlayer;
	 * var myPlayer:MaruPlayer = new MaruPlayer("http://examples.videomaru.com/video.flv");
	 * addChild(myPlayer);</pre></code>
	 * <p>This will import the required classes, create a player and add it to the display stack. The video will start playing at position 0,0. To reposition, set x and y position as you would for any other DisplayObject:</p>
	 * <code><pre>myPlayer.x = 100;
	 * myPlayer.y = 200;</pre></code>
	 * <p>In future versions, you'll be able to add more than one file using the addFile method:</p>
	 * <code>myPlayer.addFile("http://examples.videomaru.com/video_two.flv");</code><br>
	 * <p>You may also use the video.Maru XML format, documented in it's own class.</p>
	 * <p>The player has several default properties, such as autoplay = true, loopmode = 0 (no looping) and so on. We have set these to what we hope is the most useful. If you disagree with any of the default settings, please tell us. We really wanna know.</p>
	 * <em>Some properties such as autosize are true until set by the user. If the user drops the component onto the stage and does not scale it, the component will autosize upon loading the video. The same is true for this class. </em>
	 * 
	 * @see com.videomaru.IPlayable          IPlayable
	 * @see com.videomaru.MaruEvent          MaruEvent
	 * @see com.videomaru.MaruState          MaruState
	 * @see com.videomaru.MaruScaleMode      MaruScaleMode
	 * @see com.videomaru.media.PlayFLV      media.PlayFLV
	 * 
	 * @author jensa {at} flashmagazine.com
	 * @version 0.3
	 */

	public class MaruPlayer extends Sprite
	{
		// properties:
		/**
		 * Class version
		 */
		public  var maruVersion:String = "0.3";
		/**
		 * Media types supported in this version
		 */
		public  var maruFormats:Array = new Array("flv");
		/**
		 * Play automatically?
		 */
		public  var _autoplay:Boolean = true;
		/**
		 * Position automatically?
		 */
		public  var autoposition:Boolean = false;
		/**
		 * Resize automatically?
		 */
		public  var autosize:Boolean = true;
		/**
		 * Rewind media when finished playing? (to start of single file or start of playlist)
		 */
		public  var autorewind:Boolean = true;
		/**
		 * @default Default value will be set to MaruScaleMode.NO_SCALE in class constructor
		 */
		private var _scaleMode:String;
		/**
		 * The playhead's position in media file
		 */
		public  var currentposition:Number = 0;
		/**
		 * Media file duration
		 */
		public  var duration:Number = 0;
		/**
		 * Stores the current fullscreen state
		 */
		public  var fullscreen:Boolean = false;
		/**
		 * Stores the current loop mode
		 */
		 // TODO: Create a class with constants for loopmodes
		public  var loopmode:String = "NO_LOOPING";
		/**
		 * Stores the current play state
		 */
		public  var isPlaying:Boolean = false;
		/**
		 * Stores the current mute state
		 */
		public  var isMuted:Boolean = false;
		/**
		 * Stores the current playback volume
		 */
		private var _volume:Number = 1;
		/**
		 * Stores the former volume value when the sound is muted. Set to null if not in use
		 */
		private var mutedVolume:Number = 0;
		/**
		 * Set this var to get full trace output
		 */
		public  var _verbose:Boolean = false;
		/**
		 * Does events bubble to the top of the display stack?
		 */
		public  var eventsDoBubble:Boolean = true;
		
		/**
		 * Stores the frontmost playable instance
		 */
		private var topItem:IPlayable;
		/**
		 * Stores the playable instance to be faded out/removed
		 */
		private var bottomItem:IPlayable;
		/**
		 * The duration of the transition between top/bottom
		 */
		public  var fadeDuration:Number = 1;
		
		/**
		 * The number of seconds to buffer before playing. Default as is standard for the Adobe classes.
		 */
		private var _bufferTime:Number = 0.1;
		/**
		 * Smooth media when scaling
		 */
		private var _smoothing:Boolean = false;
		/**
		 * Holds the current state of the MaruPlayer according to the constants defined in MaruState.as
		 * @see MaruState
		 */
		public  var _state:String;
		//public  var streambuffer:; // TODO: Do we need this one? Should it be percentage or what?
		
		/**
		 * Number of seconds to wait before showing the media tray (if applicable)
		 * Duration of fade for showing the media tray (if applicable) 
		 */
		 // TODO: Does not belong here since coders will roll their own version if needed. Move this to component.
		public  var fadeTrayDelay:Number = 1;
		public  var fadeTrayDuration:Number = 1;
		
		// overrides
		private var _width:Number;
		private var _height:Number;
		private var _x:Number;
		private var _y:Number;
		
		public function MaruPlayer()
		{
			super();
			Log.outputLevel = 1;
			Log.dbg("MaruPlayer created ");
			scaleMode = MaruScaleMode.NO_SCALE; // Default scalemode
			state = MaruState.INITIALIZED;
			this.dispatchEvent( new MaruEvent(MaruEvent.INIT,eventsDoBubble,false ) );
		}
		
	// Public methods
	
		/**
		* @method forward
		* @return 
		*/
		public  function forward():void
		{
			Log.dbg("MaruPlayer.forward "+arguments);
		}
		public function set state(s:String):void
		{
			Log.dbg("MaruPlayer.set state "+arguments);
			_state = s;
		}
		public function get state():String
		{
			return _state;
		}
		/**
		* @method pause
		* @return 
		*/
		public function pause():void
		{
			Log.dbg("MaruPlayer.pause "+arguments);
			topItem.pause();
		}
		/**
		* @method pause
		* @return 
		*/
		public function play():void
		{
			Log.dbg("MaruPlayer.play "+arguments);
			topItem.play();
		}
	
		/**
		* If a parameter is passed, the player will start loading it. If not, the player will toggle the Play/Pause toogle.  
		* @param file The file name to play
		* @return 
		*/
		public function playfile(file:String = null):void
		{
			Log.dbg("MaruPlayer.playfile "+arguments);
			var newItem:IPlayable = newPlayable(file);
			// If the new file was valid, reorganize and start the media playback
			if( newItem != null){
				// if something is loadin into "bottomItem", we must unload it now
				if(bottomItem){ bottomItem.remove(); }
				// Next, move the topmost item (if present) into the lower slot
				if(topItem){ 
					bottomItem = topItem;
				}
				// Finally, fill the topmost slot with a new item
				topItem = newItem;
				// topItem should now start loading. Once it's sufficiently loaded, we'll fade bottomItem out and start playing topItem
			} else {
				playPauseToggle();
			}
		}
	
		/**
		* @method playPauseToggle
		* @return 
		*/
		public function playPauseToggle():void
		{
			Log.dbg("MaruPlayer.playPauseToggle "+state+" isPlaying "+isPlaying);
			if(state == MaruState.PLAYING){
				topItem.pause();
			} else if(state == MaruState.PAUSED || state == MaruState.STOPPED ){
				topItem.play();
			}
		}
	
		/**
		* @method rewind
		* @return 
		*/
		public function rewind():void
		{
			Log.dbg("MaruPlayer.rewind "+arguments);
		}
	
		/**
		* @method stop
		* @return 
		*/
		public function stop():void
		{
			Log.dbg("MaruPlayer.stop "+arguments);
			if(topItem){
				topItem.stop();
			}
		}
		/**
		* @method mute
		* @return 
		*/
		public function mute():void
		{
			Log.dbg("MaruPlayer.mute mutedVolume:"+mutedVolume+" volume:"+volume);
			if(!isMuted){
				mutedVolume = volume;
				volume = 0;
				isMuted = true;
				this.dispatchEvent( new MaruEvent(MaruEvent.MUTE,eventsDoBubble,false ) );
				this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
			}
		}
		/**
		* @method unmute
		* @return 
		*/
		public function unmute():void
		{
			Log.dbg("MaruPlayer.unmute mutedVolume:"+mutedVolume+" volume:"+volume);
			if(isMuted){
				volume = mutedVolume;
				if(topItem){
					topItem.setVol(mutedVolume);
				}
				isMuted = false;
				this.dispatchEvent( new MaruEvent(MaruEvent.UNMUTE,eventsDoBubble,false ) );
				this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
			}
		}
		/**
		* @method muteToggle
		* @return 
		*/
		public function muteToggle():void
		{
			Log.dbg("MaruPlayer.muteToggle "+arguments);
			if(!isMuted) // the sound is not muted so let's mute it
			{
				mutedVolume = volume;
				volume = 0;
				isMuted = true;
				this.dispatchEvent( new MaruEvent(MaruEvent.MUTE,eventsDoBubble,false ) );
				this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
			} else { // the sound is muted so let's turn it back on
				volume = mutedVolume;
				mutedVolume = 0;
				isMuted = false;
				this.dispatchEvent( new MaruEvent(MaruEvent.UNMUTE,eventsDoBubble,false ) );
				this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
			}
			if(topItem){
				topItem.setVol(volume);
			}
		}
		
	// getters and setters
		
		public function get autoplay():Boolean
		{
			return _autoplay;
		}
		
		public function set autoplay(val:Boolean):void
		{
			_autoplay = val;
		}
		
		/**
		* @method getFullscreen
		* @return 
		*/
		public function getFullscreen():void
		{
			Log.dbg("MaruPlayer.getFullscreen "+arguments);
			// TODO: Implement getFullscreen
		}
		/**
		* @method setFullscreen
		* @return 
		*/
		public function setFullscreen():void
		{
			Log.dbg("MaruPlayer.setFullscreen "+arguments);
			// TODO: Implement setFullscreen
		}
		
		/**
		* @method getSmoothing
		* @return 
		*/
		public function getSmoothing():Boolean
		{
			Log.dbg("MaruPlayer.getSmoothing "+arguments);
			return _smoothing;
		}
		/**
		* @method setSmoothing
		* @return 
		*/
		public function setSmoothing(val:Boolean):void
		{
			Log.dbg("MaruPlayer.setSmoothing "+arguments);
			_smoothing = val;
		}
		/**
		* @method getVolume
		* @return 
		*/
		public function get volume():Number
		{
			Log.dbg("MaruPlayer.get volume "+arguments);
			return _volume;
		}
		/**
		* @method setVolume
		* @return 
		*/
		public function set volume(v:Number):void
		{
			Log.dbg("MaruPlayer.set volume "+arguments);
			if(v>1){ v=1;}
			if(v<0){ v=0;}
			_volume = v;
			if(topItem){
				topItem.setVol(_volume);
			}
			this.dispatchEvent( new MaruEvent(MaruEvent.VOLUME_CHANGE,eventsDoBubble,false,"volume",topItem.getVol() ) );
		}
		
		/**
		* @method getPosition
		* @return 
		*/
		public function get position():Number
		{
			Log.dbg("MaruPlayer.get position "+arguments);
			if(topItem){
				return topItem.position;
			} else {
				return -1;
			}
		}
		/**
		* @method setPosition
		* @return 
		*/
		public function set position(p:Number):void
		{
			Log.dbg("MaruPlayer.set position "+arguments);
			if(topItem){
				topItem.position = p;
			}
		}
		/**
		* @method get bufferTime
		* @return 
		*/
		public function get bufferTime():Number{
			if(topItem){
				return topItem.bufferTime;
			} else {
				return -1;
			}
		}
		/**
		* @method set bufferTime
		* @return 
		*/
		public function set bufferTime(b:Number):void{
			topItem.bufferTime = b;
		}
		/**
		* @method get verbose
		* @return 
		*/
		public function get verbose():Boolean{
			return _verbose;
		}
		/**
		* @method set bufferTime
		* @return 
		*/
		public function set verbose(b:Boolean):void{
			Log.dbg("MaruPlayer.set verbose "+arguments);
			_verbose = b;
			if(_verbose){
				Log.outputLevel = 9;
			} else {
				Log.outputLevel = 0;
			}
		}
		
		/**
		* @method setSize
		* @return 
		*/
		public function setSize(w:Number, h:Number):void
		{
			Log.dbg("MaruPlayer.setSize "+arguments);
			_width = w;
			_height = h;
			autosize = false;
			if(topItem){
				topItem.setSize(_width,_height);
			}
			drawBorder();
		}
		
		public function get scaleMode():String
		{
			return _scaleMode;
		}
		public function set scaleMode(m:String):void
		{
			if(topItem){
				topItem.scaleMode = m;
			}
			if(topItem){
				topItem.setSize(_width,_height);
			}
			_scaleMode = m;
		}
		
	// private methods
		
		private function newPlayable(filename:String):IPlayable
		{
			var extension:String = filename.toLowerCase().substr(filename.length-3,filename.length);
			removeListeners(); // TODO: This should be done when unloading media after a transition, but works for this version
			switch(extension){
				case "flv" : var media:PlayFLV = new PlayFLV(filename,autoplay,scaleMode,autorewind);
				             topItem = media;
				             topItem.smoothing = _smoothing;
				             addListeners();
				             if(_width && _height){ topItem.setSize(_width,_height); }
				             addChild(media); // The item must be added here, since iPlayable's are not displayobjects
				             return media;    // No need to "break" out of switch-case, as "return" does the same.
				default    : Log.dbg("MaruPlayer.ERROR: Unknown filetype '"+extension+"'. "+maruVersion+" only supports the following file formats: "+maruFormats);
				             return null;
			}
		}
		
		/**
		* Yeah, yeah... I know this big switch is dirty, but it's so much easier to
		* keep track of what is happening when done this way... 
		*/
		private function bigToggle(e:MaruEvent):void
		{
			var t:String = e.type;
			switch(t){
				case MaruEvent.STOP               : state = MaruState.STOPPED;
				                                      Log.dbg("MaruPlayer.bigToggle "+e.type);
				                                      isPlaying = false;
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.STOP,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.COMPLETE           : state = MaruState.STOPPED;
				                                      Log.dbg("MaruPlayer.bigToggle "+e.type);
				                                      isPlaying = false;
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.COMPLETE,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.START              : state = MaruState.PLAYING;
													  Log.dbg("MaruPlayer.bigToggle "+e.type);
													  isPlaying = true;
													  topItem.setSize(_width,_height);
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.START,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.BUFFER_FULL        :   this.dispatchEvent( new MaruEvent(MaruEvent.BUFFER_FULL,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.PAUSE              : state = MaruState.PAUSED;
													  Log.dbg("MaruPlayer.bigToggle "+e.type);
													  isPlaying = false;
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.PAUSE,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.SEEK               : this.dispatchEvent( new MaruEvent(MaruEvent.SEEK,eventsDoBubble,false ) );
				                                      break;
				case MaruEvent.ASPECT             : if(scaleMode == MaruScaleMode.NO_SCALE){
				                                          _width  = topItem.width;
				                                          _height = topItem.height;
				                                          drawBorder();
				                                      }
				                                      break;
				case MaruEvent.IO_ERROR           : state = MaruState.ERROR;
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.IO_ERROR,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
													  isPlaying = false;
				                                      break;
				case MaruEvent.SECURITY_ERROR     : state = MaruState.ERROR;
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.SECURITY_ERROR,eventsDoBubble,false ) );
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.CHANGED,eventsDoBubble,false ) );
													  isPlaying = false;
				                                      break;
				case MaruEvent.METADATA           : setDuration(topItem.duration);
				                                      this.dispatchEvent( new MaruEvent(MaruEvent.METADATA,eventsDoBubble,false,e.message ) );
				                                      break;
				case MaruEvent.BUFFER_PROGRESS    : this.dispatchEvent( new MaruEvent(MaruEvent.BUFFER_PROGRESS,eventsDoBubble,false,e.message,e.value ) );
				                                      break;
				case MaruEvent.DOWNLOAD_PROGRESS  : this.dispatchEvent( new MaruEvent(MaruEvent.DOWNLOAD_PROGRESS,eventsDoBubble,false,e.message,e.value ) );
				                                      break;
				case MaruEvent.PLAY_PROGRESS      : this.dispatchEvent( new MaruEvent(MaruEvent.PLAY_PROGRESS,eventsDoBubble,false,e.message,e.value ) );
				                                      break;
				default                             : Log.dbg("unhandled event ("+e.type+") from media type "+e.currentTarget.mediatype);
				                                      break;
			}
			//Log.dbg("MaruPlayer.bigToggle state is now: "+state+" event received: "+e.type);
		}
		private function addListeners():void
		{
			// Add event listeners to active item
			topItem.addEventListener(MaruEvent.ASPECT,bigToggle);
			topItem.addEventListener(MaruEvent.IO_ERROR,bigToggle);
			topItem.addEventListener(MaruEvent.METADATA,bigToggle);
			topItem.addEventListener(MaruEvent.PAUSE,bigToggle);
			topItem.addEventListener(MaruEvent.SECURITY_ERROR,bigToggle);
			topItem.addEventListener(MaruEvent.SEEK,bigToggle);
			topItem.addEventListener(MaruEvent.START,bigToggle);
			topItem.addEventListener(MaruEvent.BUFFER_FULL,bigToggle);
			topItem.addEventListener(MaruEvent.STOP,bigToggle);
			topItem.addEventListener(MaruEvent.COMPLETE,bigToggle);
			// TODO: CHANGED and INIT not listened for?
			
			topItem.addEventListener(MaruEvent.BUFFER_PROGRESS,bigToggle);
			topItem.addEventListener(MaruEvent.DOWNLOAD_PROGRESS,bigToggle);
			topItem.addEventListener(MaruEvent.PLAY_PROGRESS,bigToggle);
		}
		private function removeListeners():void
		{
			// Remove event listeners to active item
			if(topItem){
				
				topItem.removeEventListener(MaruEvent.ASPECT,bigToggle);
				topItem.removeEventListener(MaruEvent.IO_ERROR,bigToggle);
				topItem.removeEventListener(MaruEvent.METADATA,bigToggle);
				topItem.removeEventListener(MaruEvent.PAUSE,bigToggle);
				topItem.removeEventListener(MaruEvent.SECURITY_ERROR,bigToggle);
				topItem.removeEventListener(MaruEvent.SEEK,bigToggle);
				topItem.removeEventListener(MaruEvent.START,bigToggle);
				topItem.removeEventListener(MaruEvent.BUFFER_FULL,bigToggle);
				topItem.removeEventListener(MaruEvent.STOP,bigToggle);
				topItem.removeEventListener(MaruEvent.COMPLETE,bigToggle);
				
				topItem.removeEventListener(MaruEvent.BUFFER_PROGRESS,bigToggle);
				topItem.removeEventListener(MaruEvent.DOWNLOAD_PROGRESS,bigToggle);
				topItem.removeEventListener(MaruEvent.PLAY_PROGRESS,bigToggle);
			}
		}
		private function setDuration(d:Number):void
		{
			duration = d;
		}
		/**
		 * Used by the component to make a representation on stage
		 */
		public function drawBorder():void
		{
			if(verbose){
				Log.dbg("MaruPlayer.drawBorder (executing since 'verbose' is set to true)");
				var w:Number = 320;
				var h:Number = 240;
				if(_width){ w = _width; }
				if(_height){ h = _height; }
				this.graphics.clear();
				this.graphics.lineStyle(0,0xffff00);
				this.graphics.lineTo(w,0);
				this.graphics.lineTo(w,h);
				this.graphics.lineTo(0,h);
				this.graphics.lineTo(0,0);
			}
		}
		/**
		* @method unmute
		* @return 
		*/
		public function unload():void
		{
			Log.dbg("MaruPlayer.unload");
			if(topItem){
				topItem.remove();
			}
		}
		
	// Required overrides to inherited methods
		
		override public function get width():Number
		{
			return _width;
		}
		override public function set width(w:Number):void
		{
			Log.dbg("MaruPlayer.set width "+_width);
			_width = w;
			autosize = false;
			if(topItem){
				topItem.setSize(_width,_height);
			}
			drawBorder();
		}
		override public function get height():Number
		{
			return _height;
		}
		override public function set height(h:Number):void
		{
			_height = h;
			autosize = false;
			if(topItem != null){
				topItem.setSize(_width,_height);
			}
			drawBorder();
		}
		override public function get x():Number
		{
			return _x;
		}
		override public function set x(newX:Number):void
		{
			Log.dbg("MaruPlayer.set x: "+newX);
			_x = newX;
			super.x = _x;
			drawBorder();
		}
		override public function get y():Number
		{
			return _y;
		}
		override public function set y(newY:Number):void
		{
			Log.dbg("MaruPlayer.set y: "+newY);
			_y = newY;
			super.y = _y;
			drawBorder();
		}
		
	}
}